﻿using System;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

internal class AssemblyMetadataHelper
{
    private static Guid CLSID_CorMetaDataDispenserRuntime = new Guid("1EC2DE53-75CC-11d2-9775-00A0C9B4D50C");
    private static int ENUM_TOKEN_BUF_SIZE = 4;
    private static Guid IID_IMetaDataImport = typeof(IMetaDataImport).GUID;

    public static AssemblyNameVersion GetAssemblyNameVersion(IMetaDataAssemblyImport assemblyImport)
    {
        IntPtr ptr;
        uint num2;
        uint num3;
        int num4;
        int num5;
        if (assemblyImport == null)
        {
            return null;
        }
        int assemblyFromScope = assemblyImport.GetAssemblyFromScope();
        AssemblyMetadataInfo amdInfo = new AssemblyMetadataInfo();
        assemblyImport.GetAssemblyProps(assemblyFromScope, out ptr, out num2, out num3, null, 0, out num4, ref amdInfo, out num5);
        if (num4 <= 1)
        {
            return null;
        }
        char[] strName = new char[num4 + 1];
        assemblyImport.GetAssemblyProps(assemblyFromScope, out ptr, out num2, out num3, strName, strName.Length, out num4, ref amdInfo, out num5);
        string name = new string(strName, 0, num4 - 1);
        return new AssemblyNameVersion(name, new Version(amdInfo.usMajorVersion, amdInfo.usMinorVersion));
    }

    public static AssemblyNameVersion[] GetAssemblyReferenceNameVersion(IMetaDataAssemblyImport assemblyImport)
    {
        if (assemblyImport == null)
        {
            return null;
        }
        new ArrayList();
        IntPtr zero = IntPtr.Zero;
        int[] asmRefs = new int[ENUM_TOKEN_BUF_SIZE];
        int iFetched = 0;
        ArrayList list = new ArrayList();
        try
        {
            do
            {
                assemblyImport.EnumAssemblyRefs(ref zero, asmRefs, asmRefs.Length, out iFetched);
                for (int i = 0; i < iFetched; i++)
                {
                    IntPtr ptr2;
                    IntPtr ptr3;
                    int num3;
                    int num4;
                    int num5;
                    int num6;
                    AssemblyMetadataInfo amdInfo = new AssemblyMetadataInfo();
                    assemblyImport.GetAssemblyRefProps(asmRefs[i], out ptr3, out num4, null, 0, out num5, ref amdInfo, out ptr2, out num3, out num6);
                    if (num5 > 1)
                    {
                        char[] strName = new char[num5 + 1];
                        assemblyImport.GetAssemblyRefProps(asmRefs[i], out ptr3, out num4, strName, strName.Length, out num5, ref amdInfo, out ptr2, out num3, out num6);
                        string name = new string(strName, 0, num5 - 1);
                        Version ver = new Version(amdInfo.usMajorVersion, amdInfo.usMinorVersion);
                        list.Add(new AssemblyNameVersion(name, ver));
                    }
                }
            }
            while (iFetched > 0);
        }
        finally
        {
            if (zero != IntPtr.Zero)
            {
                assemblyImport.CloseEnum(zero);
            }
        }
        return (AssemblyNameVersion[]) list.ToArray(typeof(AssemblyNameVersion));
    }

    public static IMetaDataDispenserEx GetDispenser()
    {
        return (RuntimeEnvironment.GetRuntimeInterfaceAsObject(CLSID_CorMetaDataDispenserRuntime, typeof(IMetaDataDispenserEx).GUID) as IMetaDataDispenserEx);
    }

    public static IMetaDataAssemblyImport OpenScope(IMetaDataDispenserEx dispenser, string path)
    {
        if (((dispenser == null) || (path == null)) || !File.Exists(path))
        {
            return null;
        }
        IMetaDataImport o = dispenser.OpenScope(path, 0x12, ref IID_IMetaDataImport);
        IMetaDataAssemblyImport import2 = o as IMetaDataAssemblyImport;
        if ((o != null) && (import2 == null))
        {
            Marshal.ReleaseComObject(o);
        }
        return import2;
    }

    public static void ReleaseAssemblyImport(IMetaDataAssemblyImport assemblyImport)
    {
        if (assemblyImport != null)
        {
            Marshal.ReleaseComObject(assemblyImport);
        }
    }

    public static void ReleaseDispenser(IMetaDataDispenserEx dispenser)
    {
        if (dispenser != null)
        {
            Marshal.ReleaseComObject(dispenser);
        }
    }

    [StructLayout(LayoutKind.Sequential), ComVisible(true)]
    internal struct AssemblyMetadataInfo
    {
        [MarshalAs(UnmanagedType.U2)]
        public ushort usMajorVersion;
        [MarshalAs(UnmanagedType.U2)]
        public ushort usMinorVersion;
        [MarshalAs(UnmanagedType.U2)]
        public ushort usBuildNumber;
        [MarshalAs(UnmanagedType.U2)]
        public ushort usRevisionNumber;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string szLocale;
        private uint cbLocale;
        private IntPtr rProcessor;
        private uint ulProcessor;
        private IntPtr rOS;
        private uint ulOS;
    }

    private enum CorOpenFlags : uint
    {
        ofCacheImage = 4,
        ofCopyMemory = 2,
        ofManifestMetadata = 8,
        ofNoTypeLib = 0x80,
        ofRead = 0,
        ofReadOnly = 0x10,
        ofReadWriteMask = 1,
        ofReserved = 0xffffff40,
        ofReserved1 = 0x100,
        ofReserved2 = 0x200,
        ofTakeOwnership = 0x20,
        ofWrite = 1
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("EE62470B-E94B-424e-9B7C-2F00C9249F93")]
    internal interface IMetaDataAssemblyImport
    {
        void GetAssemblyProps(int mdAsm, out IntPtr pPublicKeyPtr, out uint ucbPublicKeyBytes, out uint uHashAlg, [MarshalAs(UnmanagedType.LPArray)] char[] strName, int cchNameIn, out int cchNameRequired, ref AssemblyMetadataHelper.AssemblyMetadataInfo amdInfo, out int dwFlags);
        void GetAssemblyRefProps(int mdAsm, out IntPtr pPublicKeyPtr, out int ucbPublicKeyPtr, [MarshalAs(UnmanagedType.LPArray)] char[] strName, int cchNameIn, out int cchNameRequired, ref AssemblyMetadataHelper.AssemblyMetadataInfo amdInfo, out IntPtr ppbHashValue, out int pcbHashLength, out int dwFlags);
        void GetFileProps(int mdFile, StringBuilder strName, int cchNameIn, out int cchNameRequired, IntPtr bHashData, IntPtr cchHashBytes, IntPtr dwFileFlags);
        void GetExportedTypeProps();
        void GetManifestResourceProps();
        void EnumAssemblyRefs([In, Out] ref IntPtr phEnum, [Out, MarshalAs(UnmanagedType.LPArray)] int[] asmRefs, int fileRefCount, out int iFetched);
        void EnumFiles([In, Out] ref IntPtr phEnum, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] int[] fileRefs, int fileRefCount, out int iFetched);
        void EnumExportedTypes();
        void EnumManifestResources();
        int GetAssemblyFromScope();
        void FindExportedTypeByName();
        void FindManifestResourceByName();
        void CloseEnum([In] IntPtr phEnum);
        void FindAssembliesByName();
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("31BCFCE2-DAFB-11D2-9F81-00C04F79A0A3")]
    public interface IMetaDataDispenserEx
    {
        [return: MarshalAs(UnmanagedType.IUnknown)]
        object DefineScope();
        [return: MarshalAs(UnmanagedType.Interface)]
        AssemblyMetadataHelper.IMetaDataImport OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] string szScope, int dwOpenFlags, ref Guid riid);
        [return: MarshalAs(UnmanagedType.IUnknown)]
        object OpenScopeOnMemory();
    }

    [ComImport, Guid("fce5efa0-8bba-4f8e-a036-8f2022b08466"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMetaDataImport
    {
        [PreserveSig]
        void CloseEnum(IntPtr hEnum);
        uint CountEnum(IntPtr hEnum);
        void ResetEnum(IntPtr hEnum, uint pos);
        int EnumTypeDefs([In, Out] ref IntPtr hEnum, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] int[] pMdTokens, int nTokens);
        int EnumInterfaceImpls([In, Out] ref IntPtr hEnum, int mdTypeDef, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)] int[] pMdInterfaceTokens, int nTokens);
        void Stub_EnumTypeRefs();
        void FindTypeDefByName(string name, int enclosingToken, out int mdTypeToken);
        Guid GetScopeProps(StringBuilder szName, int cchName, out int pchName);
        int GetModuleFromScope();
        int GetTypeDefProps(int mdTypeDef, StringBuilder defName, int nMaxChars, out int nameSize, out int dwFlags);
        int GetInterfaceImplProps(int mdInterfaceImpl, out int mdTypeClass);
        int GetTypeRefProps(int mdTypeDef, out int mdScope, StringBuilder defName, int nMaxChars);
        int ResolveTypeRef(int mdTypeDef, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out AssemblyMetadataHelper.IMetaDataImport ppScope);
        void Stub_EnumMembers();
        void Stub_EnumMembersWithName();
        void Stub_EnumMethods();
        void Stub_EnumMethodsWithName();
        void Stub_EnumFields();
        void Stub_EnumFieldsWithName();
        void Stub_EnumParams();
        void Stub_EnumMemberRefs();
        void Stub_EnumMethodImpls();
        void Stub_EnumPermissionSets();
        void Stub_FindMember();
        void Stub_FindMethod();
        void Stub_FindField();
        void Stub_FindMemberRef();
        void GetMethodProps(int mdMethodDef, out int mdTypeDefClass, StringBuilder szMethod, int cchMethod, out int pchMethod, out int pdwAttrFlags, out IntPtr ppvSigBlob, out int pcbSigBlob, out int pulCodeRVA, out int pdwImplFlags);
        void GetMemberRefProps(int mdMemberRef, out int mdType, StringBuilder szMember, int cchMember, out int pchMember, out IntPtr ppvSigBlob, out int pbSig);
        void Stub_EnumProperties();
        void Stub_EnumEvents();
        void Stub_GetEventProps();
        void Stub_EnumMethodSemantics();
        void Stub_GetMethodSemantics();
        void Stub_GetClassLayout();
        void Stub_GetFieldMarshal();
        void Stub_GetRVA();
        void Stub_GetPermissionSetProps();
        void Stub_GetSigFromToken();
        [PreserveSig]
        int GetModuleRefProps(int mdModuleRef, [In, Out] StringBuilder sb, int capacity, out int pNameLen);
        void Stub_EnumModuleRefs();
        void GetTypeSpecFromToken(int mdToken, out IntPtr ppvSigBlob, out int corsigSize);
        void Stub_GetNameFromToken();
        void Stub_EnumUnresolvedMethods();
        void Stub_GetUserString();
        void Stub_GetPinvokeMap();
        void Stub_EnumSignatures();
        void Stub_EnumTypeSpecs();
        void Stub_EnumUserStrings();
        void Stub_GetParamForMethodIndex();
        int EnumCustomAttributes([In, Out] ref IntPtr pEnum, int tkScope, int tkType, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=4)] int[] tkAttributes, int nTokens);
        uint GetCustomAttributeProps(int mdToken, out int pTkObj, out int ptkType, out IntPtr ppData);
        void Stub_FindTypeRef();
        void Stub_GetMemberProps();
        void Stub_GetFieldProps();
        void Stub_GetPropertyProps();
        void Stub_GetParamProps();
        [PreserveSig]
        int GetCustomAttributeByName(int mdTokenObj, [MarshalAs(UnmanagedType.LPWStr)] string szName, out IntPtr ppData, out uint pDataSize);
        bool IsValidToken(int mdToken);
        void Stub_GetNestedClassProps();
        void Stub_GetNativeCallConvFromSig();
        void Stub_IsGlobal();
        void EnumGenericParams([In, Out] ref IntPtr hEnum, int mdToken, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)] int[] genparms, int numparms, out uint numGenericParams);
        void Stub_GetGenericParamProps();
        void Stub_GetMethodSpecProps();
        void Stub_EnumGenericParamConstraints();
        void Stub_GetGenericParamConstraintProps();
        void Stub_GetPEKind();
        void Stub_GetVersionString();
        void Stub_EnumMethodSpecs();
    }
}

